import type { VNodeChild } from 'vue';
import type { PaginationProps } from './pagination';
import type { FormProps } from '/@/components/Form';
import type {
    ColumnProps,
    TableRowSelection as ITableRowSelection,
} from 'ant-design-vue/lib/table/interface';

import { ComponentType } from './componentType';
import { VueNode } from '/@/utils/propTypes';
import { RoleEnum } from '/@/enums/roleEnum';

export declare type SortOrder = 'ascend' | 'descend';

export interface TableCurrentDataSource<T = Recordable> {
    currentDataSource: T[];
}

export interface TableRowSelection<T = any> extends ITableRowSelection {
    /**
     * Callback executed when selected rows change
     * @type Function
     */
    onChange?: (selectedRowKeys: string[] | number[], selectedRows: T[]) => any;

    /**
     * Callback executed when select/deselect one row
     * @type Function
     */
    onSelect?: (record: T, selected: boolean, selectedRows: Object[], nativeEvent: Event) => any;

    /**
     * Callback executed when select/deselect all rows
     * @type Function
     */
    onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => any;

    /**
     * Callback executed when row selection is inverted
     * @type Function
     */
    onSelectInvert?: (selectedRows: string[] | number[]) => any;
}

export interface TableCustomRecord<T> {
    record?: T;
    index?: number;
}

export interface ExpandedRowRenderRecord<T> extends TableCustomRecord<T> {
    indent?: number;
    expanded?: boolean;
}

export interface ColumnFilterItem {
    text?: string;
    value?: string;
    children?: any;
}

export interface TableCustomRecord<T = Recordable> {
    record?: T;
    index?: number;
}

export interface SorterResult {
    column: ColumnProps;
    order: SortOrder;
    field: string;
    columnKey: string;
}

export interface FetchParams {
    searchInfo?: Recordable;
    page?: number;
    sortInfo?: Recordable;
    filterInfo?: Recordable;
}

export interface GetColumnsParams {
    ignoreIndex?: boolean;
    ignoreAction?: boolean;
    sort?: boolean;
}

export type SizeType = 'default' | 'middle' | 'small' | 'large';

export interface TableActionType {
    reload: (opt?: FetchParams) => Promise<void>;
    getSelectRows: <T = Recordable>() => T[];
    clearSelectedRowKeys: () => void;
    expandAll: () => void;
    collapseAll: () => void;
    getSelectRowKeys: () => string[];
    deleteSelectRowByKey: (key: string) => void;
    setPagination: (info: Partial<PaginationProps>) => void;
    setTableData: <T = Recordable>(values: T[]) => void;
    updateTableDataRecord: (rowKey: string | number, record: Recordable) => Recordable | void;
    deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => void;
    insertTableDataRecord: (record: Recordable, index?: number) => Recordable | void;
    findTableDataRecord: (rowKey: string | number) => Recordable | void;
    getColumns: (opt?: GetColumnsParams) => BasicColumn[];
    setColumns: (columns: BasicColumn[] | string[]) => void;
    getDataSource: <T = Recordable>() => T[];
    getRawDataSource: <T = Recordable>() => T;
    setLoading: (loading: boolean) => void;
    setProps: (props: Partial<BasicTableProps>) => void;
    redoHeight: () => void;
    setSelectedRowKeys: (rowKeys: string[] | number[]) => void;
    getPaginationRef: () => PaginationProps | boolean;
    getSize: () => SizeType;
    getRowSelection: () => TableRowSelection<Recordable>;
    getCacheColumns: () => BasicColumn[];
    emit?: EmitType;
    updateTableData: (index: number, key: string, value: any) => Recordable;
    setShowPagination: (show: boolean) => Promise<void>;
    getShowPagination: () => boolean;
    setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void;
}

export interface FetchSetting {
    // 请求接口当前页数
    pageField: string;
    // 每页显示多少条
    sizeField: string;
    // 请求结果列表字段  支持 a.b.c
    listField: string;
    // 请求结果总数字段  支持 a.b.c
    totalField: string;
}

export interface TableSetting {
    redo?: boolean;
    size?: boolean;
    setting?: boolean;
    fullScreen?: boolean;
}

export interface BasicTableProps<T = any> {
    // 点击行选中
    clickToRowSelect?: boolean;
    isTreeTable?: boolean;
    // 自定义排序方法
    sortFn?: (sortInfo: SorterResult) => any;
    // 排序方法
    filterFn?: (data: Partial<Recordable<string[]>>) => any;
    // 取消表格的默认padding
    inset?: boolean;
    // 显示表格设置
    showTableSetting?: boolean;
    tableSetting?: TableSetting;
    // 斑马纹
    striped?: boolean;
    // 是否自动生成key
    autoCreateKey?: boolean;
    // 计算合计行的方法
    summaryFunc?: (...arg: any) => Recordable[];
    // 自定义合计表格内容
    summaryData?: Recordable[];
    // 是否显示合计行
    showSummary?: boolean;
    // 是否可拖拽列
    canColDrag?: boolean;
    // 接口请求对象
    api?: (...arg: any) => Promise<any>;
    // 请求之前处理参数
    beforeFetch?: Fn;
    // 自定义处理接口返回参数
    afterFetch?: Fn;
    // 查询条件请求之前处理
    handleSearchInfoFn?: Fn;
    // 请求接口配置
    fetchSetting?: Partial<FetchSetting>;
    // 立即请求接口
    immediate?: boolean;
    // 在开起搜索表单的时候，如果没有数据是否显示表格
    emptyDataIsShowTable?: boolean;
    // 额外的请求参数
    searchInfo?: Recordable;
    // 默认的排序参数
    defSort?: Recordable;
    // 使用搜索表单
    useSearchForm?: boolean;
    // 表单配置
    formConfig?: Partial<FormProps>;
    // 列配置
    columns: BasicColumn[];
    // 是否显示序号列
    showIndexColumn?: boolean;
    // 序号列配置
    indexColumnProps?: BasicColumn;
    // 是否显示操作列
    showActionColumn?: boolean,
    // 操作列配置
    actionColumn?: BasicColumn;
    // 文本超过宽度是否显示。。。
    ellipsis?: boolean;
    // 是否可以自适应高度
    canResize?: boolean;
    // 自适应高度偏移， 计算结果-偏移量
    resizeHeightOffset?: number;

    // 在分页改变的时候清空选项
    clearSelectOnPageChange?: boolean;
    //
    rowKey?: string | ((record: Recordable) => string);
    // 数据
    dataSource?: Recordable[];
    // 标题右侧提示
    titleHelpMessage?: string | string[];
    // 表格最小高度
    minHeight?: number;
    // 表格滚动最大高度
    maxHeight?: number;
    // 是否显示边框
    bordered?: boolean;
    // 分页配置
    pagination?: PaginationProps | boolean;
    // loading加载
    loading?: boolean;

    /**
     * The column contains children to display
     * @default 'children'
     * @type string | string[]
     */
    childrenColumnName?: string;

    /**
     * Override default table elements
     * @type object
     */
    components?: object;

    /**
     * Expand all rows initially
     * @default false
     * @type boolean
     */
    defaultExpandAllRows?: boolean;

    /**
     * Initial expanded row keys
     * @type string[]
     */
    defaultExpandedRowKeys?: string[];

    /**
     * Current expanded row keys
     * @type string[]
     */
    expandedRowKeys?: string[];

    /**
     * Expanded container render for each row
     * @type Function
     */
    expandedRowRender?: (record?: ExpandedRowRenderRecord<T>) => VNodeChild | JSX.Element;

    /**
     * Customize row expand Icon.
     * @type Function | VNodeChild
     */
    expandIcon?: Function | VNodeChild | JSX.Element;

    /**
     * Whether to expand row by clicking anywhere in the whole row
     * @default false
     * @type boolean
     */
    expandRowByClick?: boolean;

    /**
     * The index of `expandIcon` which column will be inserted when `expandIconAsCell` is false. default 0
     */
    expandIconColumnIndex?: number;

    /**
     * Table footer renderer
     * @type Function | VNodeChild
     */
    footer?: Function | VNodeChild | JSX.Element;

    /**
     * Indent size in pixels of tree data
     * @default 15
     * @type number
     */
    indentSize?: number;

    /**
     * i18n text including filter, sort, empty text, etc
     * @default { filterConfirm: 'Ok', filterReset: 'Reset', emptyText: 'No Data' }
     * @type object
     */
    locale?: object;

    /**
     * Row's className
     * @type Function
     */
    rowClassName?: (record: TableCustomRecord<T>, index: number) => string;

    /**
     * Row selection config
     * @type object
     */
    rowSelection?: TableRowSelection;

    /**
     * Set horizontal or vertical scrolling, can also be used to specify the width and height of the scroll area.
     * It is recommended to set a number for x, if you want to set it to true,
     * you need to add style .ant-table td { white-space: nowrap; }.
     * @type object
     */
    scroll?: { x?: number | true; y?: number };

    /**
     * Whether to show table header
     * @default true
     * @type boolean
     */
    showHeader?: boolean;

    /**
     * Size of table
     * @default 'default'
     * @type string
     */
    size?: SizeType;

    /**
     * Table title renderer
     * @type Function | ScopedSlot
     */
    title?: VNodeChild | JSX.Element | string | ((data: Recordable) => string);

    /**
     * Set props on per header row
     * @type Function
     */
    customHeaderRow?: (column: ColumnProps, index: number) => object;

    /**
     * Set props on per row
     * @type Function
     */
    customRow?: (record: T, index: number) => object;

    /**
     * `table-layout` attribute of table element
     * `fixed` when header/columns are fixed, or using `column.ellipsis`
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout
     * @version 1.5.0
     */
    tableLayout?: 'auto' | 'fixed' | string;

    /**
     * the render container of dropdowns in table
     * @param triggerNode
     * @version 1.5.0
     */
    getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;

    /**
     * Data can be changed again before rendering.
     * The default configuration of general user empty data.
     * You can configured globally through [ConfigProvider](https://antdv.com/components/config-provider-cn/)
     *
     * @version 1.5.4
     */
    transformCellText?: Function;

    /**
     * Callback executed before editable cell submit value, not for row-editor
     *
     * The cell will not submit data while callback return false
     */
    beforeEditSubmit?: (data: {
        record: Recordable;
        index: number;
        key: string | number;
        value: any;
    }) => Promise<any>;


    /**
     * Callback executed when pagination, filters or sorter is changed
     * @param pagination
     * @param filters
     * @param sorter
     * @param currentDataSource
     */
    onChange?: (pagination: any, filters: any, sorter: any, extra: any) => void;

    /**
     * Callback executed when the row expand icon is clicked
     *
     * @param expanded
     * @param record
     */
    onExpand?: (expande: boolean, record: T) => void;

    /**
     * Callback executed when the expanded rows change
     * @param expandedRows
     */
    onExpandedRowsChange?: (expandedRows: string[] | number[]) => void;

    onColumnsChange?: (data: ColumnChangeParam[]) => void;
}

export type CellFormat =
    | string
    | ((text: string, record: Recordable, index: number) => string | number)
    | Map<string | number, any>;

// @ts-ignore
export interface BasicColumn extends ColumnProps {
    children?: BasicColumn[];
    filters?: {
        text: string;
        value: string;
        children?:
            | unknown[]
            | (((props: Record<string, unknown>) => unknown[]) & (() => unknown[]) & (() => unknown[]));
    }[];

    //
    flag?: 'INDEX' | 'DEFAULT' | 'CHECKBOX' | 'RADIO' | 'ACTION';
    customTitle?: VueNode;

    slots?: Recordable;

    // Whether to hide the column by default, it can be displayed in the column configuration
    defaultHidden?: boolean;

    // Help text for table column header
    helpMessage?: string | string[];

    format?: CellFormat;

    // Editable
    edit?: boolean;
    editRow?: boolean;
    editable?: boolean;
    editComponent?: ComponentType;
    editComponentProps?: Recordable;
    editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
    editValueMap?: (value: any) => string;
    onEditRow?: () => void;
    // 权限编码控制是否显示
    auth?: RoleEnum | RoleEnum[] | string | string[];
    // 业务控制是否显示
    ifShow?: boolean | ((column: BasicColumn) => boolean);
}

export type ColumnChangeParam = {
    dataIndex: string;
    fixed: boolean | 'left' | 'right' | undefined;
    visible: boolean;
};

export interface InnerHandlers {
    onColumnsChange: (data: ColumnChangeParam[]) => void;
}
